home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / MosaicSRC / src / rexx.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-13  |  25.0 KB  |  869 lines

  1. /*
  2.  * The Rexx interface code for Amiga Mosaic.
  3.  * Copyright © 1994, Mike W. Meyer
  4.  *
  5.  * All items exported from this module will be prefixed with "Rexx". Currently,
  6.  * those are:
  7.  *
  8.  * RexxCommands - the supported Command structure for the MUI Rexx port.
  9.  * RexxLaunch - used to launch a rexx macro
  10.  * RexxDispatch - Dispatches rexx messages coming in on our port.
  11.  * RexxSignalBits - the bits we need to wait on for outstanding messages.
  12.  *
  13.  * static data items are all lower case, with "_" seperating words.
  14.  */
  15.  
  16. #include "includes.h"
  17. #include "HTML.h"
  18. #include "mosaic.h"
  19. #include "globals.h"
  20. #include "htmlgad.h"
  21. #include "protos.h"
  22.  
  23. #include <dos.h>
  24. #include <rexx/storage.h>
  25. #include <proto/rexxsyslib.h>
  26.  
  27. #include "amosaic_cat.h"
  28.  
  29. #define RETURN_BAD_ARGS    15    /* Bogus arguments in command */
  30. #define REXXNAME    "www"    /* Our macro extension */
  31. #define MAXMACRO    13    /* Maximum number of user macros */
  32. #define MAXUSERMACRO    9    /* last macro with a menu label */
  33.  
  34. static char *fetch_title(struct mark_up *, char *) ;
  35. static int stem_hrefs(struct mark_up *, char *, char *, int, struct Message *) ;
  36. static int stem_images(struct mark_up *, char *, char *, int, struct Message *) ;
  37.  
  38. extern ULONG HookEntry() ;
  39.  
  40. extern char *home_document ;
  41. extern mo_window window ;    /* Change this later */
  42.  
  43. /*
  44.  * The Hooks that MUI calls when it gets a Rexx command.
  45.  */
  46.  
  47. /* Fetch something from the WWW */
  48. #define FETCH_OPTS    "Item,Stem,URL/k,Index/k/f,Map/k/f,Form/k/f"
  49. static enum { fetch_item, fetch_stem, fetch_url,
  50.     fetch_index, fetch_map, fetch_form, fetch_count} ;
  51. static ULONG Fetch(struct Hook *h, void *o, ULONG *parms) ;
  52. static struct Hook fetch_hook = { {0}, HookEntry, &Fetch, &window} ;
  53.  
  54. /* Get information from Mosaic */
  55. #define GET_OPTS    "Item/a,Stem"
  56. static enum { get_item, get_stem, get_count} ;
  57. static ULONG Get(struct Hook *h, void *o, ULONG *parms) ;
  58. static struct Hook get_hook = { {0}, HookEntry, &Get, &window} ;
  59.  
  60. /* Jump to a document */
  61. #define JUMP_OPTS    "Item,URL/k,Index/k/f,Map/k/f,Form/k/f"
  62. static enum { jump_item, jump_url, jump_index, jump_map, jump_form, jump_count} ;
  63. static ULONG Jump(struct Hook *h, void *o, ULONG *parms) ;
  64. static struct Hook jump_hook = { {0}, HookEntry, &Jump, &window} ;
  65.  
  66. /* Open a dialog window  (Open is in dos_protos, so...) */
  67. #define OPEN_OPTS    "Item"
  68. static enum { open_item, open_count} ;
  69. static ULONG www_open(struct Hook *h, void *o, ULONG *parms) ;
  70. static struct Hook open_hook = { {0}, HookEntry, &www_open, NULL} ;
  71.  
  72. /* Twiddle misc. crap */
  73. #define OPTION_OPTS    "Item/a,To/n"
  74. static enum { option_item, option_to, option_count } ;
  75. static ULONG Option(struct Hook *h, void *o, ULONG *parms) ;
  76. static struct Hook option_hook = { {0}, HookEntry, &Option, &window} ;
  77.  
  78. /* Manipulate the screen */
  79. #define SCREEN_OPTS    "Item/a"
  80. static enum {screen_item, screen_count} ;
  81. static ULONG Screen(struct Hook *h, void *o, ULONG *parms) ;
  82. static struct Hook screen_hook = { {0}, HookEntry, &Screen, &window} ;
  83.  
  84. /* Manipulate the window */
  85. #define WINDOW_OPTS    "Item/a"
  86. static enum {window_item, window_count} ;
  87. static ULONG Window(struct Hook *h, void *o, ULONG *parms) ;
  88. static struct Hook window_hook = { {0}, HookEntry, &Window, &window} ;
  89.  
  90. /*
  91.  * The structure we pass to MUI so it can call all of the above things.
  92.  */
  93. struct MUI_Command RexxCommands[] = {
  94.     { "fetch",    FETCH_OPTS,    fetch_count,    &fetch_hook} ,
  95.     { "get",    GET_OPTS,    get_count,    &get_hook} ,
  96.     { "jump",    JUMP_OPTS,    jump_count,    &jump_hook} ,
  97.     { "open",    OPEN_OPTS,    open_count,    &open_hook} ,
  98.     { "option",    OPTION_OPTS,    option_count,    &option_hook} ,
  99.     { "screen",    SCREEN_OPTS,    screen_count,    &screen_hook} ,
  100.     { "window",    WINDOW_OPTS,    window_count,    &window_hook} ,
  101.     { NULL,        NULL,        NULL,    NULL } ,
  102.     } ;
  103.  
  104. /*
  105.  * The code that implements the hooks.
  106.  */
  107.  
  108. /* Display the named url in the given window */
  109. static enum index_types { index_index, index_map, index_form} ;
  110.  
  111. static char *
  112. make_url(char *url, char *index, int type) {
  113.     char *freeme = NULL, *out ;
  114.     unsigned x, y ;
  115.  
  116.     /* Deal with the index */
  117.     if (index) {
  118.         strtok(url, "#") ;
  119.         strtok(url, "?") ;
  120.         switch (type) {
  121.             case index_index:
  122.                 freeme = mo_escape_part(index) ;
  123.                 break ;
  124.  
  125.             case index_map:
  126.                 freeme = malloc(24) ;
  127.                 sscanf(index, "%u %u", &x, &y) ;
  128.                 sprintf(freeme, "%u,%u", x, y) ;
  129.                 break ;
  130.  
  131.             case index_form:
  132.                 return NULL ;
  133.                 /* Not implemented yet */
  134.                 break ;
  135.  
  136.             default: return NULL ;    /* Oops */
  137.             }
  138.         out = malloc(strlen(url) + strlen(freeme) + 2) ;
  139.         sprintf(out, "%s?%s", url, freeme) ;
  140.         free(freeme) ;
  141.         freeme = url = out ;
  142.         }
  143.     
  144.     mo_convert_newlines_to_spaces(url) ;
  145.     url = mo_url_canonicalize(url, NULL) ;
  146.     if (freeme) free(freeme) ;
  147.     return  url ;
  148.     }
  149.  
  150.  
  151. /* Set a stem variable's 0 index to the given count */
  152. static void
  153. stem_count(struct Message *msg, char *stem, int count) {
  154.     char var[1024], value[12] ;
  155.  
  156.     sprintf(var, "%s.0", stem) ;
  157.     sprintf(value, "%d", count) ;
  158.     SetRexxVar(msg, var, value, strlen(value)) ;
  159.     }
  160.  
  161. /* Fetch information from the Web */
  162. static ULONG
  163. Fetch(struct Hook *h, void *o, ULONG *parms) {
  164.     int count ;
  165.     char *item = (char *) parms[fetch_item] ;
  166.     char *stem = (char *) parms[fetch_stem] ;
  167.     char *url =  (char *) parms[fetch_url] ;
  168.     char *html, *oldurl, *fetched_html, *title, *freeme = NULL, buffer[1024] ;
  169.     mo_window *window = (mo_window *) h->h_Data ;
  170.     Object *app = (Object *) o ;
  171.     struct mark_up *objects ;
  172.     struct Message *msg ;
  173.     /* Free'd next time we get run; maybe use as a cache? */
  174.     static struct mark_up *fetched_objects = NULL ;
  175.     
  176.     /* Inline is an oddball - we have to do it before the URL handling */
  177.     if (!stricmp("inline", item)) {
  178.         ImageInfo *img ;
  179.         char buffer2[15] ;
  180.  
  181.         if (!url) return RETURN_BAD_ARGS ;
  182.         LoadInlinedImage(url) ;
  183.         if (!(img = mo_fetch_cached_image_data(url))) return RETURN_FAIL ;
  184.  
  185.         get(app, MUIA_Application_RexxMsg, &msg) ;
  186.         sprintf(buffer, "%s.URL", stem) ;
  187.         SetRexxVar(msg, buffer, url, strlen(url)) ;
  188.         sprintf(buffer, "%s.ISMAP", stem) ;
  189.         SetRexxVar(msg, buffer, img->ismap ? "1" : "0", 1) ;
  190.         sprintf(buffer, "%s.CURRENT", stem) ;
  191.         SetRexxVar(msg, buffer, "1", 1) ;
  192.         sprintf(buffer, "%s.WIDTH", stem) ;
  193.         sprintf(buffer2, "%d", img->width) ;
  194.         SetRexxVar(msg, buffer, buffer2, strlen(buffer2)) ;
  195.         sprintf(buffer, "%s.HEIGHT", stem) ;
  196.         sprintf(buffer2, "%d", img->height) ;
  197.         SetRexxVar(msg, buffer, buffer2, strlen(buffer2)) ;
  198.         sprintf(buffer, "%s.FILENAME", stem) ;
  199.         SetRexxVar(msg, buffer, img->fname, strlen(img->fname)) ;
  200.         return RETURN_OK ;
  201.         }
  202.  
  203.     /* Get the HTML & objects for it. */
  204.     if (!url) {
  205.         extern int binary_transfer ;
  206. //mjw        HTMLRec *inst ;
  207.  
  208.         oldurl = window->current_node->url ;
  209.         html = window->current_node->text ;
  210. //mjw        get(HTML_gad, HTML_inst, &inst) ;
  211. //mjw        objects = inst->html->html_objects ;
  212.                 objects = TO_HTML_GetHTMLObjects();
  213.         }
  214.     else {
  215.         int old_binary = binary_transfer ;
  216.         char *index =  (char *) parms[fetch_index] ;
  217.         char *form =  (char *) parms[fetch_form] ;
  218.         char *map =  (char *) parms[fetch_map] ;
  219.  
  220.         oldurl = url ;
  221.         if (index) url = make_url(url, index, index_index) ;
  222.         else if (form) url = make_url(url, form, index_form) ;
  223.         else if (map) url = make_url(url, map, index_map) ;
  224.         else url = make_url(url, NULL, index_index) ;
  225.  
  226.         binary_transfer = 0 ;
  227.         html = mo_pull_er_over(url, &fetched_html) ;
  228.         binary_transfer = old_binary ;
  229.         objects = fetched_objects = HTMLParse(fetched_objects, html) ;
  230.         }
  231.  
  232.     if (!stricmp("title", item))
  233.         set(app, MUIA_Application_RexxString,
  234.             url ? freeme = fetch_title(objects, url)
  235.                 : window->current_node->title) ;
  236.     else if (!stricmp("source", item))
  237.         set(app, MUIA_Application_RexxString, html) ;
  238.  
  239.     /* Body and head are waiting for an upgrade to the web */
  240.     else if (!stricmp("body", item)) return RETURN_FAIL ;
  241.     else if (!stricmp("head", item)) return RETURN_FAIL ;
  242.  
  243.     /* The rest of the things need the RVI */
  244.     else if (!stem) return RETURN_BAD_ARGS ;
  245.     else if (!stricmp("links", item)) {
  246.         get(app, MUIA_Application_RexxMsg, &msg) ;
  247.         stem_count(msg, stem, stem_hrefs(objects, stem, oldurl, 0, msg)) ;
  248.         }
  249.     else if (!stricmp("images", item)) {
  250.         get(app, MUIA_Application_RexxMsg, &msg) ;
  251.         stem_count(msg, stem, stem_images(objects, stem, oldurl, 0, msg)) ;
  252.         }
  253.     else if (!stricmp("urllist", item)) {
  254.         get(app, MUIA_Application_RexxMsg, &msg) ;
  255.         count = stem_hrefs(objects, stem, oldurl, 0, msg) ;
  256.         stem_count(msg, stem, stem_images(objects, stem, oldurl, count, msg)) ;
  257.         }
  258.     else if (!stricmp("document", item)) {
  259.         get(app, MUIA_Application_RexxMsg, &msg) ;
  260.  
  261.         title = url ? freeme = fetch_title(objects, url) : window->current_node->title,
  262.         sprintf(buffer, "%s.TITLE", stem) ;
  263.         SetRexxVar(msg, buffer, title, strlen(title)) ;
  264.         sprintf(buffer, "%s.SOURCE", stem) ;
  265.         SetRexxVar(msg, buffer, html, strlen(html)) ;
  266.         sprintf(buffer, "%s.TYPE", stem) ;
  267.         SetRexxVar(msg, buffer, "text/html", 9) ;
  268.  
  269.         sprintf(buffer, "%s.URLLIST", stem) ;
  270.         count = stem_hrefs(objects, buffer, oldurl, 0, msg) ;
  271.         stem_count(msg, buffer, stem_images(objects, buffer, oldurl, count, msg)) ;
  272.         }
  273.     else return RETURN_BAD_ARGS ;
  274.  
  275.     if (freeme) free(freeme) ;
  276.     if (fetched_html) free(fetched_html) ;
  277.     return RETURN_OK ;
  278.     }
  279.  
  280. /* Get information from Mosaic */
  281. static ULONG
  282. Get(struct Hook *h, void *o, ULONG *parms) {
  283.     int count ;
  284.     struct Message *msg ;
  285.     char *item = (char *) parms[get_item] ;
  286.     char *stem = (char *) parms[get_stem] ;
  287.     mo_window *window = (mo_window *) h->h_Data ;
  288.     Object *app = (Object *) o ;
  289.     Object *win = window->view ;
  290.     char buffer[1024], *freeme = NULL ;
  291.  
  292.     if (!stricmp("url", item))
  293.         set(app, MUIA_Application_RexxString, window->current_node->url) ;
  294.     else if (!stricmp("home", item))
  295.         set(app, MUIA_Application_RexxString, home_document) ;
  296.     else if (!stricmp("text", item))
  297.         set(app, MUIA_Application_RexxString,
  298.              freeme = HTMLGetText(window->scrolled_win, 0)) ;
  299.     else if (!stricmp("formatted", item))
  300.         set(app, MUIA_Application_RexxString,
  301.              freeme = HTMLGetText(window->scrolled_win, 1)) ;
  302.     else if (!stricmp("postscript", item))
  303.         set(app, MUIA_Application_RexxString,
  304.              freeme = HTMLGetText(window->scrolled_win, 2)) ;
  305.     else if (!stricmp("window", item)) {
  306.         unsigned long top, left, width, height ;
  307.         char *tmp ;
  308.  
  309.         get(win, MUIA_Window_TopEdge, &top) ;
  310.         get(win, MUIA_Window_LeftEdge, &left) ;
  311.         get(win, MUIA_Window_Height, &height) ;
  312.         get(win, MUIA_Window_Width, &width) ;
  313.         get(win, MUIA_Window_Title, &tmp) ;
  314.         sprintf(buffer, "%u/%u/%u/%u/%s", left, top, width, height, tmp) ;
  315.         set(app, MUIA_Application_RexxString, buffer) ;
  316.         }
  317.     else if (!stricmp("screen", item)) {
  318.         return RETURN_BAD_ARGS ;
  319. /* Sigh - this was supposed to work in 2.0, but doesn't
  320.         get(win, MUIA_Window_PublicScreen, &tmp) ;
  321.         set(app, MUIA_Application_RexxString, tmp) ;
  322. */
  323.         }
  324.     /* No selection in Amiga Mosaic yet */
  325.     else if (!stricmp("selection", item)) return RETURN_FAIL ;
  326.     else if (!stricmp("anchor", item)) return RETURN_FAIL ;
  327.  
  328.     /* hotlist & history require a stem */
  329.     else if (!stem) return RETURN_BAD_ARGS ;
  330.     else if (!stricmp("history", item)) {
  331.         mo_node *node ;
  332.  
  333.         get(app, MUIA_Application_RexxMsg, &msg) ;
  334.         for (count = 1, node = window->history; node != NULL;
  335.             node = node->next, count += 1) {
  336.             sprintf(buffer, "%s.%d.URL", stem, count) ;
  337.             SetRexxVar(msg, buffer, node->url, strlen(node->url)) ;
  338.             sprintf(buffer, "%s.%d.REF", stem, count) ;
  339.             SetRexxVar(msg, buffer, node->title, strlen(node->title)) ;
  340.             }
  341.         stem_count(msg, stem, count - 1) ;
  342.         }
  343.     /* No hotlist, either */
  344.     else if (!stricmp("hotlist", item)) return RETURN_FAIL ;
  345.     else return RETURN_BAD_ARGS ;
  346.  
  347.     if (freeme) free(freeme) ;
  348.     return RETURN_OK ;
  349.     }
  350.  
  351. /* Jump to different things on the WWW. */
  352. static ULONG
  353. Jump(struct Hook *h, void *o, ULONG *parms) {
  354.     int doc;
  355.     char *item = (char *) parms[jump_item] ;
  356.     char *url = (char *) parms[jump_url] ;
  357.     char *index = (char *) parms[jump_index] ;
  358.     char *map = (char *) parms[jump_map] ;
  359.     char *form = (char *) parms[jump_form] ;
  360.  
  361.     /* Must specify exactly one of item or url */
  362.     if (url) {
  363.         if (item) return RETURN_BAD_ARGS ;
  364.         if (index) url = make_url(url, index, index_index) ;
  365.         else if (form) url = make_url(url, form, index_form) ;
  366.         else if (map) url = make_url(url, map, index_map) ;
  367.         else url = make_url(url, NULL, index_index) ;
  368.         if (url) mo_load_window_text((mo_window *) h->h_Data, url, NULL) ;
  369.         else return RETURN_BAD_ARGS ;
  370.         }
  371.     else if (item) {
  372.         if (!stricmp("home", item)) doc = mo_home_document ;
  373.         else if (!stricmp("back", item)) doc = mo_back ;
  374.         else if (!stricmp("forward", item)) doc = mo_forward ;
  375.         else if (!stricmp("reload", item)) doc = mo_reload_document ;
  376.         else return RETURN_BAD_ARGS ;
  377.         DoMethod((Object *) o, MUIM_Application_ReturnID, doc) ;
  378.         }
  379.     else return RETURN_BAD_ARGS ;
  380.  
  381.     return RETURN_OK ;
  382.     }
  383.  
  384. /* Open various objects */
  385. static ULONG
  386. www_open(struct Hook *h, void *o, ULONG *parms) {
  387.     int doc ;
  388.     char *item = (char *)parms[open_item] ;
  389.     Object *app = (Object *) o ;
  390.  
  391.     if (!item) doc = mo_open_document ;
  392.     else if (!stricmp("local", item)) doc = mo_open_local_document ;
  393.     else if (!stricmp("source", item)) doc = mo_document_source ;
  394.     else if (!stricmp("history", item)) doc = mo_history_list ;
  395.     else if (!stricmp("about", item)) doc = mo_about ;
  396.     else if (!stricmp("saveas", item)) doc = mo_save_document ;
  397.     else return RETURN_BAD_ARGS ;
  398.  
  399.     DoMethod(app, MUIM_Application_ReturnID, doc) ;
  400.     return RETURN_OK ;
  401.     }
  402.  
  403. /* Twiddle Misc. crap */
  404. static ULONG
  405. Option(struct Hook *h, void *o, ULONG *parms) {
  406.     char *item = (char *)parms[option_item] ;
  407.     ULONG *to = (ULONG *)parms[option_to] ;
  408.     Object *app = (Object *) o ;
  409.     mo_window *window = (mo_window *)h->h_Data ;
  410.     char buffer[15] ;
  411.  
  412.     if (!stricmp("clear", item)) return RETURN_FAIL ;
  413.     else if (!stricmp("flush", item))
  414.         DoMethod(app, MUIM_Application_ReturnID, mo_clear_image_cache) ;
  415.     else if (!stricmp("load", item)) LoadInlinedImages() ;
  416.     else if (!stricmp("delay", item)) {
  417.         if (!to) {
  418.             sprintf(buffer, "%d", window->delay_image_loads) ;
  419.             set(app, MUIA_Application_RexxString, buffer) ;
  420.             }
  421.         else {
  422.             window->delay_image_loads = *to ;
  423.             DoMethod(app, MUIM_Application_SetMenuCheck,
  424.                     mo_delay_image_loads, *to) ;
  425.             }
  426.         }
  427.     else if (!stricmp("binary", item)) {
  428.         if (!to) {
  429.             sprintf(buffer, "%d", window->binary_transfer) ;
  430.             set(app, MUIA_Application_RexxString, buffer) ;
  431.             }
  432.         else {
  433.             window->binary_transfer = *to ;
  434.             DoMethod(app, MUIM_Application_SetMenuCheck,
  435.                     mo_binary_transfer, *to) ;
  436.             }
  437.         }
  438.     else if (!stricmp("offset", item)) {
  439.         if (!window->current_node) return RETURN_FAIL ;
  440.         if (to) {
  441.             window->current_node->docid = *to ;
  442.             ResetAmigaGadgets() ;
  443.             }
  444.         else {
  445.             sprintf(buffer, "%d", window->current_node->docid) ;
  446.             set(app, MUIA_Application_RexxString, buffer) ;
  447.             }
  448.         }
  449.     else return RETURN_BAD_ARGS ;
  450.  
  451.     return RETURN_OK ;
  452.     }
  453.  
  454. /* Manipulate the Mosaic Screen */
  455. static ULONG
  456. Screen(struct Hook *h, void *o, ULONG *parms) {
  457.     unsigned left, top ;
  458.     char *item = (char *) parms[screen_item] ;
  459.     Object *win = ((mo_window *)h->h_Data)->view ;
  460.     struct Screen *scr ;
  461.  
  462.     if (!stricmp("front", item))
  463.         DoMethod(win, MUIM_Window_ScreenToFront) ;
  464.     else if (!stricmp("back", item))
  465.         DoMethod(win, MUIM_Window_ScreenToBack) ;
  466.     else {
  467.         get(win, MUIA_Window_Screen, &scr) ;
  468.         sscanf((char *) item, "%u/%u", &left, &top) ;
  469.         if (IntuitionBase->LibNode.lib_Version >= 39)
  470.             ScreenPosition(scr, SPOS_ABSOLUTE, left, top, 0, 0) ;
  471.         else return RETURN_FAIL ;
  472.         }
  473.  
  474.     return RETURN_OK ;
  475.     }
  476.  
  477. /* Manipulate the Mosaic window */
  478. static ULONG
  479. Window(struct Hook *h, void *o, ULONG *parms) {
  480.     unsigned left, top, width, height ;
  481.     char *item = (char *) parms[window_item] ;
  482.     Object *win = ((mo_window *)h->h_Data)->view ;
  483.     struct Window *w ;
  484.  
  485.     get(win, MUIA_Window_Window, &w) ;
  486.     if (!stricmp("front", item)) DoMethod(win, MUIM_Window_ToFront) ;
  487.     else if (!stricmp("back", item)) DoMethod(win, MUIM_Window_ToBack) ;
  488.     else if (!stricmp("zip", item)) ZipWindow(w) ;
  489.     else {
  490.         sscanf((char *) item, "%u/%u/%u/%u",
  491.                 &left, &top, &width, &height) ;
  492.         ChangeWindowBox(w, left, top, width, height) ;
  493.         }
  494.  
  495.     return RETURN_OK ;
  496.     }
  497.  
  498. /*
  499.  * Rexx macro support.
  500.  */
  501. ULONG RexxSignalBits ;
  502.  
  503. static struct MsgPort *port = NULL ;
  504. static int replies_needed = 0 ;
  505.  
  506. /* Clean up the port if we're through with it */
  507. static void
  508. delete_port(void) {
  509.  
  510.     if (replies_needed) return ;
  511.     DeletePort(port) ;
  512.     port = 0 ;
  513.     RexxSignalBits = 0 ;
  514.     }
  515.  
  516. /* actually run a rexx command */
  517. static ULONG
  518. run_command(char *command) {
  519.     struct MsgPort *rexx ;
  520.     struct RexxMsg *out ;
  521.     char *muiname ;
  522.  
  523.     /* Make sure we have a port for this */
  524.     if (!(port || (port = CreatePort(NULL, 0L)))) return RETURN_FAIL ;
  525.  
  526.     /* Set up the message to run */
  527.     get(App, MUIA_Application_Base, &muiname) ;
  528.     if (!(out = CreateRexxMsg(port, REXXNAME, muiname))) {
  529.         delete_port() ;
  530.         return RETURN_FAIL ;
  531.         }
  532.     out->rm_Action = RXCOMM ;
  533.     out->rm_Args[0] = CreateArgstring(command, strlen(command)) ;
  534.  
  535.     /* Go do it to it */
  536.     Forbid() ;
  537.     if (rexx = FindPort("REXX")) PutMsg(rexx, (struct Message *) out) ;
  538.     Permit() ;
  539.  
  540.     if (rexx) {
  541.         replies_needed += 1 ;
  542.         RexxSignalBits = (1l << port->mp_SigBit) ;
  543.         return RETURN_OK ;
  544.         }
  545.     else {
  546.         DeleteRexxMsg(out) ;
  547.         delete_port() ;
  548.         return RETURN_FAIL ;
  549.         }
  550.     }
  551.  
  552. /*
  553.  * Menu strip settings - the labels are in the NewMenu structure. Since those
  554.  * aren't dynamic in any sane sense of the word, and C constants are wimpy, we
  555.  * wind up plugging them directly into the structure, knowing the offset.  Yuch.
  556.  */
  557.  
  558. #define MENU_OFFSET 37
  559.  
  560. /* Pointers to the strings we're going to run as macros */
  561. static char *rexx_macro[MAXMACRO] ;
  562.  
  563. void
  564. RexxMenu(int item, char *string) {
  565.     char *label, *command, *p ;
  566.  
  567.     extern char *RexxMacroNames[10];
  568.  
  569.     item -= mo_macro_1 ;
  570.     if (item < 0 || MAXMACRO <= item) return ;
  571.  
  572.     label = strdup(string) ;    /* My own copy to work with */
  573.  
  574.     if (item > MAXUSERMACRO) {
  575.         rexx_macro[item] = label ;
  576.         return ;
  577.     }
  578.  
  579.     if (!(command = strchr(label, '|'))) {
  580.         RexxMacroNames[item]=strdup("~");
  581.         return ;
  582.     }
  583.  
  584.     *command++ = '\0' ;
  585.     command = stpblk(command) ; 
  586.  
  587.     RexxMacroNames[item]=strdup(label);
  588.  
  589.     rexx_macro[item] = command ;
  590.     }
  591.  
  592. /*
  593.  * RexxLaunch - used to launch macros from inside of MUI. For now, we don't
  594.  * deal cleanly with having multiple macros running. If all this works
  595.  * (I.e. - MUI doesn't hose us yet again), I'll fix that.
  596.  */
  597.  
  598. /* The callback hook for macros launched from the Rexx->Macro menu. */
  599. static ULONG
  600. macro_callback(struct Hook *h, void *o, int *msg) {
  601.     mo_window *win = (mo_window *)h->h_Data ;
  602.     Object *window = (Object *)o ;
  603.     struct Window *w = NULL ;
  604.     char *string, buffer[255] ;
  605.     struct FileRequester *fr ;
  606.  
  607.     switch (*msg) {
  608.     case 0:    /* Run*/
  609.         set(window, MUIA_Window_Open, FALSE) ;
  610.         get(win->macro_string, MUIA_String_Contents, &string) ;
  611.         run_command(string) ;
  612.         break ;
  613.  
  614.     case 1:    /* Cancel */
  615.         set(window, MUIA_Window_Open, FALSE) ;
  616.         break ;
  617.  
  618.         }
  619.     return 0 ;
  620.     }
  621.  
  622. ULONG
  623. RexxLaunch(int which, mo_window *win) {
  624.  
  625.     /* Now, figure out what to do */
  626.     if (which < -1 || MAXMACRO <= which) return RETURN_ERROR ;
  627.  
  628.     if (which >= 0 && rexx_macro[which])
  629.         return run_command(rexx_macro[which]) ;
  630.     else if (which != -1) return RETURN_ERROR ;
  631.  
  632.     /* Going to get a macro from the user */
  633.     if (!win->macro_win) {
  634.         struct Hook *hook = malloc(sizeof(struct Hook)) ;
  635.         Object *b_run, *b_clear, *b_cancel ;
  636.  
  637.         hook->h_Entry = HookEntry ;
  638.         hook->h_SubEntry = macro_callback ;
  639.         hook->h_Data = win ;
  640.  
  641.         win->macro_win = WindowObject ,
  642.             MUIA_Window_Title, GetamosaicString(MSG_REQ_MACRO_TITLE),
  643.             MUIA_Window_RefWindow, win->view,
  644.             MUIA_Window_ID,MAKE_ID('R','E','X','X'),
  645.             WindowContents, VGroup,
  646.                 Child, HGroup,
  647.                     Child, Label2(GetamosaicString(MSG_REQ_MACRO_MACRO)),
  648.                     Child,PopaslObject,
  649.                         MUIA_Popstring_String,win->macro_string=StringObject,StringFrame,MUIA_String_MaxLen,512,MUIA_String_Contents,"rexx:",End,
  650.                         MUIA_Popstring_Button,PopButton(MUII_PopDrawer),
  651.                         ASLFR_TitleText,GetamosaicString(MSG_REQ_MACRO_FILEREQ_TITLE),
  652.                         ASLFR_DoPatterns,TRUE,
  653.                         ASLFR_InitialPattern,"#?."REXXNAME,
  654.                         End,
  655.                     End,
  656.                 Child, HGroup,
  657.                     MUIA_Group_SameWidth,TRUE,
  658.                     Child, b_run = SimpleButton(GetamosaicString(MSG_REQ_MACRO_RUN)),
  659.                     Child, b_clear = SimpleButton(GetamosaicString(MSG_REQ_MACRO_CLEAR)),
  660.                     Child, b_cancel = SimpleButton(GetamosaicString(MSG_REQ_MACRO_CANCEL)),
  661.                     End,
  662.                 End,
  663.             End;
  664.         DoMethod(win->macro_win, MUIM_Notify,
  665.             MUIA_Window_CloseRequest, TRUE,
  666.             win->macro_win, 3, MUIM_Set, MUIA_Window_Open, FALSE);
  667.         DoMethod(b_run, MUIM_Notify, MUIA_Pressed, FALSE,
  668.             win->macro_win, 3, MUIM_CallHook, hook, 0);
  669.         DoMethod(b_cancel, MUIM_Notify, MUIA_Pressed, FALSE,
  670.             win->macro_win, 3, MUIM_CallHook, hook, 1);
  671.         DoMethod(b_clear, MUIM_Notify, MUIA_Pressed, FALSE,
  672.             win->macro_string, 3, MUIM_Set, MUIA_String_Contents, NULL);
  673.         DoMethod(win->macro_string, MUIM_Notify, MUIA_String_Acknowledge,
  674.             MUIV_EveryTime, win->macro_win, 3, MUIM_CallHook,
  675.             hook, 0);
  676.  
  677.         DoMethod(App, OM_ADDMEMBER, win->macro_win);
  678.         }
  679.  
  680.     set(win->macro_win, MUIA_Window_Open, TRUE) ;
  681.     return RETURN_OK ;
  682.     }
  683.  
  684. /*
  685.  * RexxDispatch - just eat reply messages to our port. If it's
  686.  * anything but a reply message, we're royally hosed. So we set the Rexx
  687.  * result code (hoping that it really is a rexx result) to a failure,
  688.  * and reply to it.
  689.  */
  690. void
  691. RexxDispatch(void) {
  692.     struct RexxMsg *msg ;
  693.  
  694.     while (msg = (struct RexxMsg *) GetMsg(port))
  695.         if (msg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG) {
  696.             msg->rm_Result1 = RETURN_FAIL ;
  697.             ReplyMsg((struct Message *) msg) ;
  698.             }
  699.         else {
  700.             DeleteArgstring(msg->rm_Args[0]) ;
  701.             DeleteRexxMsg(msg) ;
  702.             replies_needed -= 1 ;
  703.             }
  704.  
  705.     delete_port() ;
  706.     }
  707.  
  708. /*
  709.  * Clean up any outstanding Rexx messages.
  710.  */
  711. void
  712. RexxQuit(void) {
  713.  
  714.     while (replies_needed) {
  715.         WaitPort(port) ;
  716.         RexxDispatch() ;
  717.         }
  718.     }
  719.  
  720. /*
  721.  * HTML parsing - we have to do this ourselves, as the current parsing is
  722.  * wrapped up in the HTML Widget. If we ever grow multiple windows, this might
  723.  * all get replaced by a widget with no attached window. Until then, it's
  724.  * not clear how reentrant the gadget parsing is, so we don't risk it.
  725.  */
  726. static char *
  727. fetch_title(struct mark_up *objects, char *url) {
  728.     char *title = NULL, *tmp ;
  729.     extern char *mo_grok_alternate_title(char *, char *) ;
  730.  
  731.     /* Skip down to the title (if we find one) */
  732.     while (objects && objects->type != M_TITLE && !objects->is_end)
  733.         objects = objects->next ;
  734.  
  735.     /* Pull all the text from inside the title */
  736.     while (objects) {
  737.         if (objects->type == M_NONE)
  738.             if (!title) title = strdup(objects->text) ;
  739.             else {
  740.                 tmp = malloc(strlen(title) +
  741.                          strlen(objects->text) +
  742.                          1) ;
  743.                 sprintf(tmp, "%s%s", title, objects->text) ;
  744.                 free(title) ;
  745.                 title = tmp ;
  746.                 }
  747.         else if (objects->type == M_TITLE && objects->is_end)
  748.             return title ;
  749.         objects = objects->next ;
  750.         }
  751.  
  752.     if (title) free(title) ;    /* No </title> */
  753.  
  754.     title = mo_grok_alternate_title(url, NULL) ;
  755.     }
  756.  
  757. static int
  758. stem_hrefs(struct mark_up *objects,
  759.     char *stem,
  760.     char *oldurl,
  761.     int count,
  762.     struct Message *msg) {
  763.  
  764.     char *ref = NULL, *url = NULL, *tmp, buffer[1024] ;
  765.  
  766.     while (objects) {
  767.         if (objects->type == M_ANCHOR) {
  768.             if (!objects->is_end) {
  769.                 if (url) free(url) ;
  770.                 if (url = ParseMarkTag(objects->start, MT_ANCHOR, AT_HREF)) {
  771.                     if (*url) {
  772.                         tmp = mo_url_canonicalize(url,
  773.                                     oldurl) ;
  774.                         free(url) ;
  775.                         url = tmp ;
  776.                         }
  777.                     else {
  778.                         free(url) ;
  779.                         url = NULL ;
  780.                         }
  781.                     }
  782.                 }
  783.             else if (url) {    /* Got a pair! */
  784.                 sprintf(buffer, "%s.%d.URL", stem, count + 1) ;
  785.                 SetRexxVar(msg, buffer, url, strlen(url)) ;
  786.                 sprintf(buffer, "%s.%d.REF", stem, count + 1) ;
  787.                 if (ref) {
  788.                     SetRexxVar(msg, buffer, ref, strlen(ref)) ;
  789.                     free(ref) ;
  790.                     ref = NULL ;
  791.                     }
  792.                 else SetRexxVar(msg, buffer, "", 0) ;
  793.                 count = count + 1 ;
  794.                 free(url) ;
  795.                 url = NULL ;
  796.                 }
  797.             else if (ref) {
  798.                 free(ref) ;
  799.                 ref = NULL ;
  800.                 }
  801.             }
  802.         else if (url && objects->type == M_NONE)
  803.             if (!ref) ref = strdup(objects->text) ;
  804.             else {
  805.                 tmp = malloc(strlen(ref) +
  806.                          strlen(objects->text) +
  807.                          1) ;
  808.                 sprintf(tmp, "%s%s", ref, objects->text) ;
  809.                 free(ref) ;
  810.                 ref = tmp ;
  811.                 }
  812.         objects = objects->next ;
  813.         }
  814.  
  815.     if (url) free(url) ;
  816.     if (ref) free(ref) ;
  817.     return count ;
  818.     }
  819.  
  820. static int
  821. stem_images(struct mark_up *objects,
  822.     char *stem,
  823.     char *oldurl,
  824.     int count,
  825.     struct Message *msg) {
  826.  
  827.     ImageInfo *img ;
  828.     int ismap ;
  829.     char *url, *url2, buffer[1024], buffer2[12] ;
  830.  
  831.     while (objects) {
  832.         if (objects->type == M_IMAGE) {
  833.             url = ParseMarkTag(objects->start, MT_IMAGE, "ISMAP") ;
  834.             ismap = (int) url ;
  835.             if (url) free(url) ;
  836.             if (url = ParseMarkTag(objects->start, MT_IMAGE, "SRC")) {
  837.                 if (*url) {
  838.                     url2 = mo_url_canonicalize(url, oldurl) ;
  839.                     sprintf(buffer, "%s.%d.URL", stem, count + 1) ;
  840.                     SetRexxVar(msg, buffer, url2, strlen(url2)) ;
  841.                     sprintf(buffer, "%s.%d.ISMAP", stem, count + 1) ;
  842.                     SetRexxVar(msg, buffer, ismap ? "1" : "0", 1) ;
  843.  
  844.                     sprintf(buffer, "%s.%d.CURRENT", stem, count + 1) ;
  845.                     if (!(img = mo_fetch_cached_image_data(url2)))
  846.                         SetRexxVar(msg, buffer, "0", 1) ;
  847.                     else {
  848.                         SetRexxVar(msg, buffer, "1", 1) ;
  849.                         sprintf(buffer, "%s.%d.WIDTH", stem, count + 1) ;
  850.                         sprintf(buffer2, "%d", img->width) ;
  851.                         SetRexxVar(msg, buffer, buffer2, strlen(buffer2)) ;
  852.                         sprintf(buffer, "%s.%d.HEIGHT", stem, count + 1) ;
  853.                         sprintf(buffer2, "%d", img->height) ;
  854.                         SetRexxVar(msg, buffer, buffer2, strlen(buffer2)) ;
  855.                         sprintf(buffer, "%s.%d.FILENAME", stem, count + 1) ;
  856.                         SetRexxVar(msg, buffer, img->fname, strlen(img->fname)) ;
  857.                         }
  858.                     count = count + 1 ;
  859.                     free(url2) ;
  860.                     }
  861.                 free(url) ;
  862.                 }
  863.             }
  864.         objects = objects->next ;
  865.         }
  866.  
  867.     return count ;
  868.     }
  869.